home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Personal Computer World 2009 February
/
PCWFEB09.iso
/
Software
/
Linux
/
Kubuntu 8.10
/
kubuntu-8.10-desktop-i386.iso
/
casper
/
filesystem.squashfs
/
usr
/
bin
/
openssl-vulnkey
< prev
next >
Wrap
Text File
|
2008-06-19
|
6KB
|
205 lines
#!/usr/bin/python
#
# openssl-vulnkey: check a database of sha1'd static key hashes for
# known vulnerable keys
# Copyright (C) 2008 Canonical Ltd.
# Author: Jamie Strandboge <jamie@canonical.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2,
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from optparse import OptionParser
import os
import re
import sha
import subprocess
import sys
import tempfile
import shutil
version = "0.3.3"
db_prefix = "/usr/share/openssl-blacklist/blacklist.RSA-"
db_lines = []
parser = OptionParser(usage="%prog FILE [FILE]", \
version="%prog: " + version, \
description="This program checks if FILEs are known " + \
"vulnerable static keys")
parser.add_option("-q", "--quiet", action="store_true", dest="quiet", \
help="be quiet")
parser.add_option("-b", "--bits", dest="bits", \
help="number of bits (requires -m)")
parser.add_option("-m", "--modulus", dest="modulus", \
help="modulus to check (requires -b)")
(options, args) = parser.parse_args()
if not ((options.modulus and options.bits) or args):
parser.print_help()
sys.exit(1)
def cmd(command, input = None, stderr = subprocess.PIPE, stdout = subprocess.PIPE, stdin = None):
'''Try to execute given command (array) and return its stdout, or return
a textual error if it failed.'''
try:
sp = subprocess.Popen(command, stdin=stdin, stdout=stdout, stderr=stderr, close_fds=True)
except OSError, e:
return [127, str(e)]
out = sp.communicate(input)[0]
return [sp.returncode,out]
def get_contents(file):
'''Determine the type of certificate it is. Returns empty string if
unsupported.'''
args = ['-modulus', '-text', '-in', file]
rc, report = cmd(['openssl', 'rsa'] + args)
if rc == 0:
return ("rsa", report)
rc, report = cmd(['openssl', 'x509'] + args)
if rc == 0:
return ("x509", report)
rc, report = cmd(['openssl', 'req'] + args)
if rc == 0:
return ("req", report)
return ("", report)
def get_bits(contents, type):
'''Find bit length of file. Returns empty string if unsupported.'''
for line in contents:
leading = "Private-Key: "
if type == "x509" or type == "req":
leading = "RSA Public Key: "
# TODO: don't hardcode these
if leading + "(512" in contents:
return "512"
elif leading + "(1024" in contents:
return "1024"
elif leading + "(2048" in contents:
return "2048"
elif leading + "(4096" in contents:
return "4096"
elif leading + "(8192" in contents:
return "8192"
return ""
def get_modulus(contents):
'''Find modulus of file'''
for line in contents.split('\n'):
if re.match(r'^Modulus=', line):
return line + '\n'
return ""
def get_exponent(contents):
'''Find exponent of file. Returns empty string if unsupported.'''
if "Exponent: 65537 " in contents:
return "65537"
return ""
def check_db(bits, last, modulus, name=""):
'''Check modulus against database'''
global db_lines
if last != bits:
db = db_prefix + bits
# Read in the database
try:
fh = open(db, 'r')
except:
try:
print >> sys.stderr, "WARN: could not open database for %s " \
"bits. Skipped %s" % (bits, name)
except IOError:
pass
return False
db_lines = fh.read().split('\n')
fh.close()
key = sha.sha(modulus).hexdigest()
#print "bits: %s\nmodulus: %s\nkey: %s\nkey80: %s" % (bits, modulus, key, key[20:])
if key[20:] in db_lines:
if not options.quiet:
print "COMPROMISED: %s %s" % (key, name)
return True
else:
if not options.quiet:
print "Not blacklisted: %s %s" % (key, name)
return False
last_bits = ""
found = False
if options.bits and options.modulus:
found = check_db(options.bits, last_bits, "Modulus=" + options.modulus + \
"\n")
else:
# Check each file
for f in args:
realname = f
if f == "-":
# dump stdin to tmpfile, operate on tmpfile instead
temp = tempfile.NamedTemporaryFile()
shutil.copyfileobj(sys.stdin,temp)
temp.flush()
f = temp.name
if not os.path.exists(f):
if not options.quiet:
print >> sys.stderr, "'%s' could not be opened (skipping)" % \
(realname)
continue
(type, contents) = get_contents(f)
if type == "":
if not options.quiet:
print >> sys.stderr, "'%s' is not x509, req or rsa (skipping)" \
% (realname)
continue
exp = get_exponent(contents)
if exp == "":
if not options.quiet:
print >> sys.stderr, "Unsupported exponent '%s' (skipping)" % \
(realname)
continue
bits = get_bits(contents, type)
if bits == "":
if not options.quiet:
print >> sys.stderr, "Key has unknown validity: %s" % \
(realname)
continue
modulus = get_modulus(contents)
if modulus == "":
if not options.quiet:
print >> sys.stderr, "Problem finding modulus: %s" % (realname)
continue
found = check_db(bits, last_bits, modulus, realname)
last_bits = bits
if found:
sys.exit(1)